﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Elentok.Common.Wpf.Helpers;

namespace Elentok.Common.Wpf.Controls
{
  /// <summary>
  /// Handles drag-and-drop in a <see cref="ListView"/>
  /// </summary>
  /// <typeparam name="TItem">The data context type of each list view item</typeparam>
  public class ListViewDragDropManager<TItem>
  {
    #region Private Members
    private bool isDragging;
    private Point dragStartPoint;
    private ListView listView;
    #endregion

    #region Ctor
    /// <summary>
    /// Initializes a new instance of the <see cref="ListViewDragDropManager&lt;TItem&gt;"/> class
    /// </summary>
    /// <param name="listView"></param>
    public ListViewDragDropManager(ListView listView)
    {
      this.listView = listView;

      listView.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(ListView_PreviewMouseLeftButtonDown);
      listView.PreviewMouseMove += new MouseEventHandler(ListView_PreviewMouseMove);
    }
    #endregion

    #region Helper Methods

    private List<TItem> GetDraggedItems()
    {
      List<TItem> draggedItems = new List<TItem>();
      foreach (TItem item in this.listView.SelectedItems)
      {
        draggedItems.Add(item);
      }
      return draggedItems;
    }

    private void ListView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
      Point mousePosition = e.GetPosition(this.listView);
      ListViewItem item = this.listView.GetListViewItemFromPoint(mousePosition);

      if (item == null)
        return;

      if (item != null)
      {
        this.isDragging = true;
        this.dragStartPoint = e.GetPosition(null);
      }
    }

    private void ListView_PreviewMouseMove(object sender, MouseEventArgs e)
    {
      if (isDragging)
      {
        if (e.LeftButton != MouseButtonState.Pressed)
          isDragging = false;
        else
        {
          Point mousePos = e.GetPosition(null);
          Vector diff = dragStartPoint - mousePos;

          if (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance &&
              Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)
          {
            DataObject data = new DataObject(GetDraggedItems());
            DragDrop.DoDragDrop(this.listView, data, DragDropEffects.Move);
          }
        }
      }
    }

    #endregion
  }
}
